/*
 * Copyright 2002-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import java.io.Serializable;

import org.springframework.util.Assert;

/**
 * 用于创建代理的配置的方便超类，确保所有代理创建者具有一致的属性。
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see AdvisedSupport
 */
public class ProxyConfig implements Serializable {

	/** use serialVersionUID from Spring 1.2 for interoperability. */
	private static final long serialVersionUID = -8409359707199703185L;


	private boolean proxyTargetClass = false;

	private boolean optimize = false;

	boolean opaque = false;

	boolean exposeProxy = false;

	private boolean frozen = false;


	/**
	 * 设置是否直接代理目标类，而不是仅仅代理特定的接口。默认设置是“false”。
	 *
	 * 将此设置为"true"以强制代理TargetSource的公开目标类。
	 * 如果目标类是一个接口，那么将为给定的接口创建一个JDK代理。
	 * 如果目标类是任何其他类，则将为给定类创建一个CGLIB代理。
	 *
	 * 注意: 根据具体代理工厂的配置，如果没有指定接口(并且没有激活接口自动检测)，也将应用代理目标类行为。
	 * @see org.springframework.aop.TargetSource#getTargetClass()
	 */
	public void setProxyTargetClass(boolean proxyTargetClass) {
		this.proxyTargetClass = proxyTargetClass;
	}

	/**
	 * 返回是否直接代理目标类以及任何接口。
	 */
	public boolean isProxyTargetClass() {
		return this.proxyTargetClass;
	}

	/**
	 * 设置代理是否应该执行主动优化。“aggressive optimizations”的确切含义在代理之间是不同的，但通常会有一些权衡。
	 * 默认设置是“false”。
	 *
	 * 例如，优化通常意味着在创建代理后advice更改不会生效。
	 * 因此，默认情况下禁用优化。
	 * 如果其他设置排除了优化，“true”的优化值可能会被忽略:例如，如果“exposeProxy”被设置为“true”，而这与优化不兼容。
	 */
	public void setOptimize(boolean optimize) {
		this.optimize = optimize;
	}

	/**
	 * 返回代理是否应该执行积极的优化。
	 */
	public boolean isOptimize() {
		return this.optimize;
	}

	/**
	 * 设置由此配置创建的代理是否应该防止被转换为{@link Advised}以查询代理的状态。
	 * 默认值是“false”，这意味着任何AOP代理都可以被转换为{@link Advised}.
	 */
	public void setOpaque(boolean opaque) {
		this.opaque = opaque;
	}

	/**
	 * 返回由此配置创建的代理是否应该为防止被转换为{@link Advised}。
	 */
	public boolean isOpaque() {
		return this.opaque;
	}

	/**
	 * 设置代理是否应该被AOP框架作为ThreadLocal公开，以便通过AopContext类进行检索。
	 * 如果一个被advised的对象需要对自己调用另一个被advised的方法，这是很有用的。
	 * (如果它使用{@code this}，调用将不会被通知)。
	 * 默认为“false”，以避免不必要的额外拦截。
	 * 这意味着不能保证AopContext访问在被advised对象的任何方法中都能一致地工作。
	 */
	public void setExposeProxy(boolean exposeProxy) {
		this.exposeProxy = exposeProxy;
	}

	/**
	 * 返回AOP代理是否将公开的AOP代理每次调用。
	 */
	public boolean isExposeProxy() {
		return this.exposeProxy;
	}

	/**
	 * 设置是否应该冻结该配置。
	 * 当配置被冻结时，不能进行任何advice更改。
	 * 这对于优化很有用，当我们不希望调用者能够在转换为Advised后操作配置时也很有用。
	 */
	public void setFrozen(boolean frozen) {
		this.frozen = frozen;
	}

	/**
	 * 返回配置是否被冻结，并且不能进行任何advice更改。
	 */
	public boolean isFrozen() {
		return this.frozen;
	}


	/**
	 * 从另一个配置对象中复制配置。
	 * @param other object to copy configuration from
	 */
	public void copyFrom(ProxyConfig other) {
		Assert.notNull(other, "Other ProxyConfig object must not be null");
		this.proxyTargetClass = other.proxyTargetClass;
		this.optimize = other.optimize;
		this.exposeProxy = other.exposeProxy;
		this.frozen = other.frozen;
		this.opaque = other.opaque;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("proxyTargetClass=").append(this.proxyTargetClass).append("; ");
		sb.append("optimize=").append(this.optimize).append("; ");
		sb.append("opaque=").append(this.opaque).append("; ");
		sb.append("exposeProxy=").append(this.exposeProxy).append("; ");
		sb.append("frozen=").append(this.frozen);
		return sb.toString();
	}

}
